<template>
  <vxe-pulldown
    ref="pullRef"
    placement="bottom-start"
    :style="{ width: width ? width + 'px' : '100%' }"
    transfer
  >
    <template #default>
      <ltext
        ref="jselectRef"
        :model-value="text"
        :disabled="disabled"
        :clearable="clearable"
        :size="size"
        :placeholder="placeholder"
        :showMore="showMore"
        :autoSelect="autoSelect"
        :width="width"
        :height="height"
        @focus="focusEvent"
        @blur="blurEvent"
        @keydown="keydownEvent"
        @clear="clear"
        @input="changeInput"
      />
    </template>
    <template #dropdown>
      <div class="pull-wrapper" ref="wrapperRef">
        <template v-if="state.list.length > 0">
          <div
            :id="'id' + item[valueKey]"
            :class="['list-item2', currentIndex === index ? 'active' : '']"
            v-for="(item, index) in state.list"
            :key="index"
            @mousedown.prevent="mouseDown($event, item)"
          >
            <span>{{ item[labelKey] }}</span>
          </div>
        </template>
      </div>
      <div class="add-row" v-if="addItem" @mousedown="addItemClick">
        <el-space>
          <i class="plus"> </i>
          <span>新增</span>
        </el-space>
      </div>
    </template>
  </vxe-pulldown>
</template>

<script>
// 是id为主
import tool from "@/utils/tool";
export default {
  props:{
    width: {type: [String, Number], default: 150},
    modelValue: {type: [String, Number], default: ''},
    invId: {type: [String, Number], default: ''},
    sql: {type: String, default: ''},
    size: {type: String, default: 'default'},
    valueKey: {type: String, default: 'id'},
    labelKey: {type: String, default: 'name'},
    searchKey: {type: String, default: ''},
    height: {type: [String, Number], default: ''},
    showMore: {type: Boolean, default: false},
    addItem: {type: Boolean, default: false},
    disabled: {type: Boolean, default: false},
    autoSelect: {type: Boolean, default: false},
    clearable: {type: Boolean, default: true},
    list: {type: [String, Array], default: ''},
    focusOpen: {type: Boolean, default: true}, // focus自动打开
    readonly: {type: Boolean, default: false}, // 必填
    required: {type: Boolean, default: false}, // 必填
    pinYin: {type: Boolean, default: false}, // 拼音
    border: {type: Boolean, default: true}, // 禁用
    className: {type: String, default: ''}, // 自定义样式
    borderColor: {type: String, default: ''}, // 边框色
    bgColor: {type: String, default: ''}, // 背景色
    listWidth: {type: Number, default: 0}, // 下拉框宽度
    cat: {type: String, default: ''}, // 取数据cat分类
    placeholder: {type: String, default: ''}, // 取数据cat分类
    options: {type: Array, default: () => { return [] }}, // 如果传入值
  },
  data () {
    return {
      show: false,
      state: {
        list: this.list
      },
      text: '',
      currentIndex: -1,
    }
  },
  emits: ['update:modelValue', 'change', 'enter', 'Esc', 'down', 'up', 'left', 'right', 'itemAdd'],
  watch: {
    list: {
      handler (val) {
        this.state.list = val
      },
      deep: true
    },
    modelValue (val) {
      if(val) {
        this.setInitText(val)
      }
      else {
        this.text = ''
      }
    }
  },
  mounted() {
    // this.setInitText(this.modelValue)
  },
  methods: {
    setInitText (val) {
      if(this.state.list.length === 0) {
        tool.post('common/dropdown', {cat: this.cat, id: val}).then(ret => {
          if(ret.stat) {
            if(ret.data && ret.data.length > 0) {
              this.text = ret.data
            }
          }
        })
      }
    },
    focusEvent () {
      if(this.focusOpen) {
        this.currentIndex = -1
        if(!this.modelValue)
        this.changeInput(this.modelValue)
      }
    },
    blurEvent () {
      this.hidePanel()
    },
    isOpen () {
      return this.$refs.pullRef.isPanelVisible()
    },
    keydownEvent (e) {
      let key = e.key ? e.key : e.$event.key
      let start = e.target.selectionStart // 光标位置
      switch (key) {
        case 'Enter': {

          if(this.currentIndex > -1 && this.currentIndex < this.state.list.length) {
            this.setData(this.state.list[this.currentIndex])
          }
          if(!this.isOpen()) {
            this.$emit('enter')
          }
        } break
        case 'ArrowLeft': {
          if(start === 0) {
            this.$emit('left')
          }
        }
          break
        case 'ArrowRight': {
          if(start === (this.modelValue?tool.xe.toString(this.modelValue).length:0)) {
            this.$emit('right')
          }
        }
          break
        case 'ArrowDown': {
          if(!e.ctrlKey) {
            if(this.isOpen()) {
              if(this.currentIndex < this.state.list.length - 1) {
                this.currentIndex++
                this.scrollToOption(true, this.state.list[this.currentIndex])
              } else {
                let optWrapperElem = this.$refs.wrapperRef;
                this.currentIndex = 0
                optWrapperElem.scrollTo(0, 0)
              }
            }
            else {
              this.$emit('down')
            }
          }
        } break
        case 'ArrowUp': {
          if(!e.ctrlKey) {
            if(this.isOpen()) {
              if(this.currentIndex > 0 && this.currentIndex <= (this.state.list.length-1)) {
                this.currentIndex--
              } else {
                this.currentIndex = this.state.list.length - 1
              }
              this.scrollToOption(false, this.state.list[this.currentIndex])
            }
            else {
              this.$emit('up')
            }
          }
        } break
        case 'Escape': {
          this.hidePanel()
          this.$emit('Esc')
        } break
      }
    },
    clear () {
      this.$emit('update:modelValue', null)
      this.$emit('change', null)
      this.currentIndex = -1
      this.hidePanel()
    },
    changeInput (value) {
      if(this.disabled) return
      this.$emit('update:modelValue', value)
      let searchTxt = value?tool.xe.trim(value):'';
      if(this.list.length > 0) {
        if(searchTxt) {
          this.state.list = this.list.filter(row => {
            return row[this.labelKey].indexOf(searchTxt) !== -1
          })
        }
        this.openPanel()
      }
      else if (this.sql) {
        let sql = this.sql
        if(searchTxt) {
          if(this.pinYin) {
            sql += ` and (${this.labelKey} like '%${searchTxt}%' or pinYin like '%${searchTxt}%') `
          }
          else {
            sql += ` and ${this.labelKey} like '%${searchTxt}%' `
          }
        }
        tool.post('common/doSql', {sql: sql}).then(ret => {
          if(ret.data && ret.data.length > 0) {
            this.state.list = ret.data
            this.openPanel()
          }
        })
      }
      else if (this.cat) {
        this.state.list = []
        tool.post('common/dropdown', {cat: this.cat, keyWord: searchTxt, invId: this.invId}).then(ret => {
          if(ret.stat) {
            if(ret.data && ret.data.length > 0) {
              this.state.list = ret.data
              this.openPanel()
            }
          }
        })
      }
    },
    openPanel () {
      if(this.$refs.pullRef)
      this.$refs.pullRef.showPanel()
    },
    hidePanel () {
      if(this.$refs.pullRef)
      this.$refs.pullRef.hidePanel()
    },
    mouseDown (e, item) {
      e.preventDefault()
      this.setData(item)
      setTimeout(() => {
        this.$emit('enter')
      }, 0)
    },
    scrollToOption (isAlignBottom, item) {
      let optWrapperElem = this.$refs.wrapperRef;
      let panelElem = this.$refs.wrapperRef;
      let optElem = panelElem.querySelector("#id"+item.id);
      if (optWrapperElem && optElem) {
        let wrapperHeight = panelElem.offsetHeight;
        let offsetPadding = 5;
        if (isAlignBottom) {
          if (optElem.offsetTop + optElem.offsetHeight - panelElem.scrollTop > wrapperHeight) {
            optWrapperElem.scrollTo(0, optElem.offsetTop + optElem.offsetHeight - wrapperHeight)
          }
        }
        else {
          optWrapperElem.scrollTo(0, optElem.offsetTop - offsetPadding)
        }
      }
    },
    setData (item) {
      let id = item[this.valueKey]
      let text = item[this.labelKey]
      this.text = text
      this.$emit('update:modelValue', id)
      this.$emit('change', item)
      this.hidePanel()
    },
    down (e) {
      e.preventDefault()
    },
    addItemClick () {
      this.$emit('itemAdd')
    },
  }
}
</script>

<style lang="scss">
.list-item2 {
  height: 30px;
  line-height: 30px;
  padding-left: 5px;
  padding-right: 30px;
  white-space: nowrap;
  &.active {
    background-color: #dcdfe6;
  }
  &:hover {
    background-color: #dcdfe6;
    cursor: pointer;
  }
}
.el-input-group__append {
  padding: 0 2px !important;
}
.more {
  &:hover {
    cursor: pointer;
  }
}
.pull-wrapper {
  height: 200px;
  overflow: auto;
  //box-shadow: 0 2px 5px 0 #E5E5E5;
  box-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.1);
  width: auto;
}
.add-row {
  height: 25px;
  line-height: 25px;
  text-align: center;
  color: #8a8f97;
  background-color: var(--el-bg-color-page);
  border-left: var(--el-border);
  border-right: var(--el-border);
  border-bottom: var(--el-border);
  &:hover {
    cursor: pointer;
    color: #1e9fff;
  }
}
</style>